IDEAL
JUMPS
include "device.inc"
include "consts.inc"

$$Language      EQU     PASCAL
$$StackPtr      EQU     FARSTACK

IFDEF BGI30

$$Model         EQU     SMALL

ELSE

$$Model         EQU     TINY

ENDIF

include "macros.inc"

CODESEG
                BGI     OAKVGA

DATASEG

IFDEF BGI30

                db      2               ; liczba selektorów do konwersji
                dw      offset SelA000  ; offset tablicy selektorów
                db      0               ; liczba adresów przerwań do konwersji
                dw      0               ; offset tablicy dwusłów z numerem przerwania w najmłodszym bajcie
                db      0               ; liczba buforów do alokacji
                dw      0               ; adres do tablicy trójsłów
                                        ; pierwsze słowo -> liczba paragrafów do zaalokowania
                                        ; drugie słowo -> uzyskuje adres bufora do trybu real
                                        ; trzecie słowo -> uzyskuje adres bufora do trybu protected
                ORG     0Ah
                dw      0               ; segment danych
CpuMode         db      0               ; 0 -> tryb real, 1 -> tryb protected

ENDIF

LABEL           video_adr       WORD
SelA000         dw      0A000h
Sel0040         dw      00040h
sel_inc         dw      01000h

; tablica adresów wejść do procedur graficznych

DDOVEC          dw      install         ; inicjalizacja i instalacja drivera
                dw      init            ; inicjalizacja drivera do wyprowadzania
                dw      clear           ; czyszczenie ekranu
                dw      post            ; wyjście z trybu graficznego
                dw      move            ; ustawienie CP
                dw      draw            ; linia z CP do (X,Y)
                dw      vect            ; linia (X1,Y1) - (X2,Y2)
                dw      EMULATE         ; wypełniony wielokąt - funkcja emulowana przez jądro systemu
                dw      EMULATE         ; wypełniony słupek trójwymiarowy z CP do (X,Y)
                dw      patbar          ; wypełniony prostokąt (X1,Y1) - (X2,Y2)
                dw      EMULATE         ; wycinek koła - emulowany
                dw      EMULATE         ; wypełniony wycinek elipsy - emulowany
                dw      EMULATE         ; wypełniona elipsa - emulowana
                dw      palette         ; ładowanie wejścia w palecie
                dw      allpalette      ; ładowanie całej palety
                dw      color           ; kolor wykreślania i tła
                dw      fillstyle       ; styl wypełniania
                dw      linestyle       ; styl linii
                dw      textstyle       ; styl wykreślania tekstów
                dw      text            ; wyprowadzanie tekstu od CP
                dw      textsiz         ; pytanie o rozmiar tekstu
                dw      RESERVED        ; zarezerwowane
                dw      floodfill       ; wypełnianie otoczonego regionu - brak
                dw      getpix          ; odczyt koloru piksela
                dw      putpix          ; zapis piksela
                dw      bitmaputil      ; pytanie o tablicę funkcji dodatkowych
                dw      savebitmap      ; zapisanie w pamięci fragmentu obrazu
                dw      restorebitmap   ; odtworzenie z pamięci fragmentu obrazu
                dw      setclip         ; definiowanie okienka obcinającego
                dw      color_query     ; pytanie o tablice kolorów
                dw      35 DUP (RESERVED)       ; wejścia zarezerwowane

; tablica funkcji dodatkowych

BITMAPUTILVEC   dw      gotographic     ; przejście do trybu pikslowego
                dw      exitgraphic     ; opuszczenie trybu pikslowego
                dw      putpixel        ; zapis piksela
                dw      getpixel        ; odczyt koloru piksela
                dw      bits_pix        ; zwraca liczbę bitów na piksel
                dw      setpage         ; ustawienie strony aktywnej
                dw      setpage         ; ustawienie strony widocznej
                dw      setwritemode    ; ustawienie trybu wykreślania

; zmienne globalne

; tablice statusu trybów

stat_tables     $status     <0,0, 319,199, 319,199,10000,7020, 8900,8h,8h,90h,90h>
                $status     <0,0, 639,479, 639,479,10000,6940,10800,8h,8h,90h,90h>
                $status     <0,0, 799,599, 799,599,10000,8400, 8930,8h,8h,90h,90h>
                $status     <0,0,1023,767,1023,767,10000,7060,10630,8h,8h,90h,90h>

; zmienne dotyczące wyprowadzania tekstów

font_number     db      ?               ; numer fontu
font_orient     db      ?               ; orientacja fontu
fontXsize       dw      8               ; rozmiar poziomy fontu w pikselach
fontYsize       dw      8               ; rozmiar pionowy fontu w pikselach
fontXmult       db      ?               ; mnożnik poziomy fontu
fontYmult       db      ?               ; mnożnik pionowy fontu
fontXmarg       dw      ?               ; margines poziomy
fontYmarg       dw      ?               ; margines pionowy
font_buffer     db      8 dup (?)       ; bufor (wyprowadzanie pionowe)
font8x8lo       dd      0               ; pierwsze 128 znaków
font8x8hi       dd      0               ; drugie 128 znaków

; zmienne systemowe, zależne od sprzętu

current_map     db      0               ; aktualny segment w pamięci video
mode_number     db      ?               ; numer trybu

; aktualne wartości różnych parametrów globalnych

current_x       dw      0               ; aktualna współrzędna X
current_y       dw      0               ; aktualna współrzędna Y
draw_color      db      15              ; kolor wykreślania
fill_color      db      0               ; kolor wypełniania
fill_no         db      1               ; numer stylu wypełniania
bkgr_color      db      0               ; kolor tła
current_status  dw      ?               ; offset aktualnej tablicy statusu
pix_per_line    dw      ?               ; liczba pikseli w linii
left_x          dw      0               ; współrzędna X1 okienka obcinającego
top_y           dw      0               ; współrzędna Y1 okienka obcinającego
right_x         dw      ?               ; współrzędna X2 okienka obcinającego
bottom_y        dw      ?               ; współrzędna Y2 okienka obcinającego
write_mode      db      COPY_PUT        ; tryb wykreślania
line_width      db      1               ; grubość wyprowadzanej linii


; nazwy trybów

mode_names      db      24,'320 x 200 256 colors VGA' ,0,0,0
                db      25,'640 x 480 256 colors SVGA',0,0
                db      25,'800 x 600 256 colors SVGA',0,0
                db      26,'1024 x 768 256 colors SVGA',0

; style wykreślania linii

line_styles     dw      0FFFFh                  ; solid line style
                dw      0CCCCh                  ; dotted line
                dw      0FC78h                  ; center line
                dw      0F8F8h                  ; dashed line

; aktualny styl wykreślania linii

line_style      dw      0FFFFh

; style wypełniania

fill_styles     db      0FFh, 0FFh, 000h, 000h, 0FFh, 0FFh, 000h, 000h  ; line fill
                db      001h, 002h, 004h, 008h, 010h, 020h, 040h, 080h  ; lt slash fill
                db      0E0h, 0C1h, 083h, 007h, 00Eh, 01Ch, 038h, 070h  ; slash fill
                db      0E0h, 070h, 038h, 01Ch, 00Eh, 007h, 083h, 0C1h  ; backslash fill
                db      080h, 040h, 020h, 010h, 008h, 004h, 002h, 001h  ; lt backslash fill
                db      0FFh, 088h, 088h, 088h, 0FFh, 088h, 088h, 088h  ; hatch fill
                db      081h, 042h, 024h, 018h, 018h, 024h, 042h, 081h  ; xhatch fill
                db      0CCh, 033h, 0CCh, 033h, 0CCh, 033h, 0CCh, 033h  ; interleave fill
                db      080h, 000h, 008h, 000h, 080h, 000h, 008h, 000h  ; wide dot fill
                db      088h, 000h, 022h, 000h, 088h, 000h, 022h, 000h  ; close dot fill

; aktualny styl wypełniania

fill_style      db      8 dup (0)

; domyślna paleta

default_palette db      10h,00h,01h,02h,03h,04h,05h,14h,07h
                db          38h,39h,3Ah,3Bh,3Ch,3Dh,3Eh,3Fh

; zmienne procedury floodfill i pomocniczych

BorderColor     db      0
StackStart      dw      0
StackCurr       dw      0
UpXLimit        dw      0
UpXLimit1       dw      0

MOldInt33       dd      0

MOldX           dw      0
MOldY           dw      0
MOlddx          dw      0
MOlddy          dw      0
MBuffer         db      256 dup (0)
MBufferEmpty    db      0

MfDraw          db      0

MHotSpotX       dw      0
MHotSpotY       dw      0
MCursorTbl      dw      2 dup (16 dup (0))

MArrowCursor    dw      0, 0
                dw      09FFFh, 08FFFh, 087FFh, 083FFh
                dw      081FFh, 080FFh, 0807Fh, 0803Fh
                dw      0801Fh, 0800Fh, 080FFh, 0887Fh
                dw      0987Fh, 0FC3Fh, 0FC3Fh, 0FE3Fh
                dw      00000h, 02000h, 03000h, 03800h
                dw      03C00h, 03E00h, 03F00h, 03F80h
                dw      03FC0h, 03E00h, 03600h, 02300h
                dw      00300h, 00180h, 00180h, 00000h

MUserRoutine    dd      0
MUserMask       dw      0

MTrapX1         dw      0
MTrapY1         dw      0
MTrapX2         dw      0
MTrapY2         dw      0

CODESEG

; procedury

; SETSEG
; Funkcja używana do ustawienia na karcie odpowiedniego segmentu pamięci
; do transferów
;    wejście :  AL - numer segmentu
;    wyjście :  brak
;

PROC            setseg          NEAR
                mov     ah,al           ; w AL - segment do ustawienia
                shl     ah,1
                shl     ah,1
                shl     ah,1
                shl     ah,1
                or      ah,al
                mov     dx,03DEh        ; do DX numer portu
                mov     al,11h          ; tu w AX dana do przesłania
                out     dx,ax           ; wyprowadź daną
                ret
ENDP            setseg

; INSTALL
; 1. Instalacja drivera
;    wejście :  AL = 0
;               CL - numer trybu dla urządzenia
;    wyjście :  ES : BX - wskazują na tablicę statusu urządzenia
;    uwaga   :  ta funkcja nie przełącza do trybu graficznego a jedynie
;               inicjuje sterownik
; 2. Pytanie o liczbę trybów
;    wejście :  AL = 1
;    wyjście :  CX - liczba trybów obsługiwanych przez urządzenie
; 3. Pytanie o nazwę trybu
;    wejście :  AL = 2
;               CX - numer trybu o który pytamy
;    wyjście :  ES : BX - wskaźnik do paskalowego ciągu znaków zawierającego
;                         nazwę

PROC            install         NEAR
IFDEF BGI30
                LOCAL   @@DPMIBuf : WORD : 25
ENDIF
                or      al,al
                jnz     @@8
IFNDEF BGI30
                mov     [DGROUP@],ds
ENDIF
                mov     al,size $status ; instaluj, do AL długość tablicy statusu
                mul     cl              ; w CL numer trybu
                mov     bx,ax           ; AX do BX
                add     bx,offset stat_tables   ; dodaj do BX offset pierwszej tablicy
                mov     al,13h
                or      cl,cl
                jz      @@1
                mov     al,53h
                cmp     cl,1
                je      @@1
                inc     al
                cmp     cl,2
                je      @@1
                add     al,5
        @@1:    mov     [mode_number],al        ; zapamiętaj nr trybu dla BIOS'a
                mov     ax,[($status ptr bx).$xres]     ; pobierz rozdzielczość X
                mov     [right_x],ax    ; i zainicjuj okienko obcinające
                inc     ax              ; zwiększ o jeden
                mov     [pix_per_line],ax       ; tu liczba pikseli w linii
                mov     ax,[($status ptr bx).$yres]     ; pobierz rozdzielczość Y
                mov     [bottom_y],ax   ; i zainicjuj okienko obcinające
                mov     [left_x],0
                mov     [top_y],0
                mov     [current_status],bx     ; zapamiętaj adres aktualnej tablicy statusu
IFDEF BGI30
                cmp     [CpuMode],0
                jne     @@2
ENDIF
                push    bp
                mov     ax,1130h
                mov     bh,3
                int     10h
                mov     [word font8x8lo+2],es
                mov     [word font8x8lo],bp
                mov     ax,1130h
                mov     bh,4
                int     10h
                mov     [word font8x8hi+2],es
                mov     [word font8x8hi],bp
                pop     bp
IFDEF BGI30
                jmp     @@7
        @@2:    mov     ax,ss
                mov     es,ax
                lea     di,[@@DPMIBuf]
                mov     cx,25
                xor     ax,ax
                rep     stosw
                mov     [@@DPMIBuf+28],1130h
                mov     [byte @@DPMIBuf+17],3
                mov     ax,300h
                mov     bx,10h
                xor     cx,cx
                lea     di,[@@DPMIBuf]
                int     31h
                jc      @@3
                mov     bx,[@@DPMIBuf+34]
                mov     ax,2
                int     31h
                jc      @@3
                mov     dx,[@@DPMIBuf+8]
                mov     [word font8x8lo+2],ax
                mov     [word font8x8lo],dx
                jmp     @@4
        @@3:    mov     bx,[current_status]
                mov     [($status ptr bx).$stat],grError
        @@4:    mov     [@@DPMIBuf+28],1130h
                mov     [byte @@DPMIBuf+17],4
                mov     ax,300h
                mov     bx,10h
                xor     cx,cx
                lea     di,[@@DPMIBuf]
                int     31h
                jc      @@5
                mov     bx,[@@DPMIBuf+34]
                mov     ax,2
                int     31h
                jc      @@5
                mov     dx,[@@DPMIBuf+8]
                mov     [word font8x8hi+2],ax
                mov     [word font8x8hi],dx
                jmp     @@6
        @@5:    mov     bx,[current_status]
                mov     [($status ptr bx).$stat],grError
        @@6:    mov     ax,3
                int     31h
                mov     [sel_inc],ax
        @@7:
ENDIF
                call    InstallMouse
                mov     bx,[current_status]
                mov     es,[DGROUP@]
                jmp     @@10
        @@8:    cmp     al,1
                jne     @@9
                mov     cx,4
                jmp     @@10
        @@9:    mov     es,[DGROUP@]
                mov     al,28           ; tak -> do AL długość łańcuchów z nazwą
                mul     cl              ; w CL numer trybu o który pytamy
                mov     bx,ax           ; AX do BX
                add     bx,offset mode_names    ; dodaj do BX offset pierwszej
        @@10:   ret
ENDP            install

; INIT
; Inicjuje urządzenie do wyprowadzania
;    wejście :  ES : BX - wskażnik do tablicy informacyjnej urządzenia (DIT)
;    wyjście :  brak
; DIT :
; struct DIT
;        db     0               ; kolor tła do inicjacji
;        db     0               ; flaga inicjacji
;                               ; 0A5h - nie inicjuj, inaczej - inicjuj
;        db     64 dup (0)      ; zarezerwowane

PROC            init    NEAR
                mov     al,[es:bx]      ; do AL kolor tła
                mov     [bkgr_color],al ; zapamiętaj w zmiennej
                mov     al,[mode_number]; pobierz nr trybu dla BIOS'a
                xor     ah,ah           ; funkcja 0 - ustaw tryb
                int     10h             ; przerwania 10h
                mov     bh,[bkgr_color] ; do BH kolor tła
                mov     ax,1000h        ; funkcja 10h
                xor     bl,bl           ; do BL numer rejestru (0 - tło)
                int     10h             ; wołaj przerwanie VIDEO
                mov     [current_map],0 ; zainicjuj zmienną
                xor     ax,ax
                int     33h
                ret
ENDP            init

; CLEAR
; Czyszczenie ekranu
;    wejście :  brak
;    wyjście :  brak

PROC            clear   NEAR
                mov     es,[video_adr]  ; załaduj adres segmentu video
                cmp     [mode_number],13h       ; tryb 13h ?
                je      @@2             ; tak -> skocz
                mov     bx,[current_status]     ; pobierz adres tablicy statusu
                mov     ax,[($status ptr bx).$yres]     ; rozdzielczość Y
                inc     ax              ; liczba linii ekranu
                mul     [pix_per_line]  ; liczba pikseli na linię
                mov     [current_map],dl; na wyjściu będzie ostatni segment
                mov     bx,dx           ; DX do BX (liczba segmentów)
                xor     si,si           ; zeruj SI
                xor     di,di           ; i DI
        @@1:    mov     ax,si           ; w SI nr aktualnego segmentu
                call    setseg          ; ustaw segment
                mov     al,[bkgr_color] ; kolor tła do AL
                mov     ah,al           ; i do AH
                mov     cx,8000h        ; 32768 słów do przesłania
                rep     stosw           ; czyść
                inc     si              ; następna mapa
                cmp     si,bx           ; koniec ?
                jbe     @@1             ; nie -> skocz
                ret
        @@2:    xor     di,di
                mov     al,[bkgr_color]
                mov     ah,al
                mov     cx,32000        ; 32000 słów do przesłania
                rep     stosw           ; czyść
                ret
ENDP            clear

; POST
; Wyjście z trybu graficzego

PROC            post    NEAR
                call    UninstallMouse
                ret
ENDP            post                    ; wszystko załatwia za nas kernel

; MOVE
; Aktualizacja CP
;    wejście :  AX - nowy X
;               BX - nowy Y
;    wyjście :  brak

PROC            move            NEAR
                mov     [current_x],ax  ; nowy x
                mov     [current_y],bx  ; i nowy y
                ret
ENDP            move

; DRAW
; Rysuje linię z CP do (X,Y)
;    wejście :  AX - końcowy X
;               BX - końcowy Y
;    wyjście :  brak

PROC            draw            NEAR
                mov     cx,ax           ; do CX końcowy X
                mov     dx,bx           ; a do DX końcowy Y
                xchg    [current_x],ax  ; uaktualnij CP
                xchg    [current_y],bx  ; i pobierz współrzędne początku
ENDP            draw                    ; resztę zrobi następna procedura

; VECT
; Rysuje linię z (X1,Y1) do (X2,Y2)
;    wejście :  AX = X1
;               BX = Y1
;               CX = X2
;               DX = Y2
;    wyjście :  brak

PROC            vect            NEAR
                LOCAL   @@X1 : WORD, @@Y1 : WORD, @@X2 : WORD, @@Y2 : WORD,\
                        @@deltaX : WORD, @@deltaY : WORD,\
                        @@stepX : WORD, @@stepY : WORD,\
                        @@PutProc : WORD
                mov     [@@X1],ax       ; zapamiętaj X1,
                mov     [@@Y1],bx       ; Y1,
                mov     [@@X2],cx       ; X2
                mov     [@@Y2],dx       ; i Y2
                mov     di,1            ; do DI 1
                sub     cx,ax           ; do CX X2 - X1
                jge     @@1             ; czy CX >= 0 ?, tak -> skocz
                neg     cx              ; nie -> do CX -CX
                neg     di              ; do DI -DI
        @@1:    mov     [@@deltaX],cx   ; zapamiętaj deltaX
                mov     [@@stepX],di    ; i stepX
                mov     di,1            ; a tutaj to samo dla Y
                sub     dx,bx
                jge     @@2
                neg     dx
                neg     di
        @@2:    mov     [@@deltaY],dx
                mov     [@@stepY],di
                xor     bh,bh
                mov     bl,[write_mode]
                shl     bx,1
                mov     bx,[@@jumptbl+bx]
                mov     [@@PutProc],bx
                xor     bx,bx           ; zeruj BX
                or      cx,cx           ; czy deltaX == 0 ?
                jnz     @@3             ; nie -> skocz
                mov     bx,-1           ; tak -> do BX -1
        @@3:    mov     si,[line_style] ; do SI styl wykreślania linii
                mov     es,[video_adr]  ; adres segmentu pamięci video do ES
                mov     cl,[draw_color] ; kolor wykreślania do CL
                jmp     @@8             ; skocz
        @@4:    rol     si,1            ; czy wykreślamy następny punkt ?
                jnc     @@6             ; nie -> skocz dalej
                mov     ax,[pix_per_line]     ; do AX szerokość linii w pikselach
                mul     [@@Y1]          ; mnóż przez aktualny Y
                add     ax,[@@X1]       ; dodaj aktualny X
                adc     dl,0            ; w DL nr segmentu video na karcie
                mov     di,ax           ; w DI offset w segmencie
                cmp     dl,[current_map]      ; czy przeprogramować kartę ?
                je      @@5             ; nie -> skocz
                mov     al,dl           ; tak -> zrób to
                mov     [current_map],dl
                call    setseg
        @@5:    call    [@@PutProc]
        @@6:    or      bx,bx           ; bx >= 0 ?
                jge     @@7             ; tak -> skocz dalej
                mov     ax,[@@stepY]    ; do AX stepY
                add     [@@Y1],ax       ; uaktualnij Y
                add     bx,[@@deltaX]   ; dodaj deltaX do BX
                jmp     @@8             ; skocz
        @@7:    mov     ax,[@@stepX]    ; do AX stepX
                add     [@@X1],ax       ; uaktualnij X
                sub     bx,[@@deltaY]   ; odejmij deltaY od BX
        @@8:    mov     ax,[@@X1]       ; aktualne X do AX
                cmp     ax,[@@X2]       ; porównaj z X2
                jne     @@4             ; nierówne - kontunuuj kreślenie
                mov     ax,[@@Y1]       ; aktualne Y do AX
                cmp     ax,[@@Y2]       ; porównaj z Y2
                jne     @@4             ; nierówne - kontunuuj wykreślanie
                rol     si,1            ; wykreślamy ostatni punkt
                jnc     @@10            ; nie trzeba -> skocz
                mov     ax,[pix_per_line]     ; do AX szerokość linii w pikselach
                mul     [@@Y1]          ; mnóż przez aktualny Y
                add     ax,[@@X1]       ; dodaj aktualny X
                adc     dl,0            ; w DL nr segmentu video na karcie
                mov     di,ax           ; w DI offset w segmencie
                cmp     dl,[current_map]      ; czy przeprogramować kartę ?
                je      @@9             ; nie -> skocz
                mov     al,dl           ; tak -> zrób to
                mov     [current_map],dl
                call    setseg
        @@9:    call    [@@PutProc]
        @@10:   ret                     ; koniec
@@CopyPut:      mov     [es:di],cl
                retn
@@XorPut:       xor     [es:di],cl
                retn
@@jumptbl       dw      @@CopyPut
                dw      @@XorPut
ENDP            vect

; PATBAR
; Wypełniony prostokąt (X1,Y1) - (X2,Y2)
;    wejście :  AX = X1
;               BX = Y1
;               CX = X2
;               DX = Y2
;    wyjście :  brak
; Funkcja jedynie wypełnia prostokąt (nie są rysowane boki)

PROC            patbar          NEAR
                LOCAL   @@X1 : WORD, @@Y1 : WORD, @@Y2 : WORD,\
                        @@deltaX : WORD, @@sdl : BYTE, @@scx : WORD,\
                        @@sdi : WORD
                cmp     ax,cx           ; X1 < X2
                jb      @@1             ; tak -> skocz
                xchg    ax,cx           ; nie -> zamień miejscami
        @@1:    cmp     bx,dx           ; Y1 < Y2
                jb      @@2             ; tak -> skocz
                xchg    bx,dx           ; nie -> zamień miejscami
        @@2:    mov     es,[video_adr]  ; ładuj adres VIDEO-RAM
                mov     [@@X1],ax       ; zapamiętaj X1
                mov     [@@Y1],bx       ; i Y1
                mov     [@@Y2],dx       ; i Y2
                sub     cx,ax           ; policz deltaX
                inc     cx              ; zwiększ o jeden
                mov     [@@deltaX],cx   ; i zapamiętaj
                mov     al,[fill_color] ; do AL kolor wypełniania
                mov     ah,al           ; i do AH też
                mov     si,ax           ; prześlij AX do SI
                mov     ax,[pix_per_line]       ; do AX szerokość linii
                mul     bx              ; pomnóż przez Y1
                add     ax,[@@X1]       ; dodaj X1
                adc     dl,0            ; po tym w DL nr segmentu
                mov     di,ax           ; a w DI offset
                mov     [@@sdl],dl      ; zapamiętaj DL
                cmp     [fill_no],1     ; SOLID lub BACKGROUND FILL ?
                jbe     @@11            ; tak -> idź zrobić to szybciej
        @@3:    mov     [@@sdi],di      ; zapamiętaj DI
                and     bx,7            ; tylko trzy ostatnie bity są ważne
                mov     bl,[fill_style+bx]      ; pobierz styl na daną linijkę
                mov     cl,[byte ptr @@X1]      ; do CL mniej znacząca część X1
                and     cl,7            ; tylko trzy bity znowu
                rol     bl,cl           ; przekręć styl linijkę na początek dla danej kolumny
; powyższe kombinacje alpejskie z wzorcem wydają się być bez sensu,
; ale one coś dają - wzorki wykreślane odzielnymi wywołaniami funkcji będą
; do siebie pasowały - linijki zawsze na siebie zajdą
                mov     cx,[@@deltaX]   ; do cx deltaX
                mov     al,[@@sdl]      ; do AL @@sdl
                cmp     [current_map],al; zmieniamy mapę ?
                je      @@4             ; nie -> to skocz
                mov     [current_map],al; tak -> to już wiesz jak to zrobić
                call    setseg
        @@4:    test    di,1            ; nieparzysty adres ?
                jz      @@5             ; nie -> skocz
                dec     cx              ; tak -> zmniejsz licznik o jeden
                xor     al,al           ; zeruj al
                rol     bl,1            ; wykreślić ?
                sbb     al,0            ; nie -> w AL 0, tak -> 0FFh
                and     ax,si           ; po tym w AL 0 (tło) lub nr koloru
                stosb                   ; prześlij bajt
                or      di,di           ; DI = 0 ?
                jnz     @@5             ; nie -> skocz
                mov     al,[current_map]; tak -> zmień mapę
                inc     al              ; na następną
                mov     [current_map],al
                call    setseg
        @@5:    shr     cx,1            ; parzysta liczba bajtów do przesłania ?
                pushf
                jcxz    @@9             ; jeśli teraz w CX 0 to skocz
                shl     cx,1            ; pomnóż CX przez 2
                mov     [@@scx],cx      ; i zapamiętaj
                neg     cx              ; dopełnij dwójkowo
                cmp     di,cx           ; DI > CX
                ja      @@7             ; tak -> skocz
                neg     cx              ; nie -> przywróć stary CX
                shr     cx,1            ; jeszcze raz
                mov     [@@scx],0       ; tu 0
                jmp     @@8             ; i skocz - nie musisz zmieniać segmentu
        @@7:    mov     cx,di           ; DI do CX
                neg     cx              ; dopełnij dwójkowo
                sub     [@@scx],cx      ; odejmij od scx (tu liczba przesłań po zmianie segmentu)
                shr     cx,1            ; podziel przez 2
        @@8:    xor     ax,ax           ; zeruj AX
                rol     bl,1            ; wyświetlić ?
                sbb     al,0            ; tak -> w AL 0FFh, nie -> 0
                rol     bl,1            ; co z następnym ?
                sbb     ah,0            ; tak -> w AH 0FFh, nie -> 0
                and     ax,si           ; w AL i AH kolor lub 0
                stosw                   ; prześlij
                loop    @@8             ; sprawdź czy koniec, nie -> skocz
                or      di,di           ; zmienić segment ?
                jnz     @@9             ; nie -> skocz
                mov     al,[current_map]; tu już wiesz o co chodzi
                inc     al
                mov     [current_map],al
                call    setseg
                cmp     [@@scx],0       ; coś jeszcze zostało ?
                je      @@9             ; nie -> skocz
                mov     cx,[@@scx]      ; tak -> do CX liczba przesłań bajtów
                shr     cx,1            ; a tu już słów
                mov     [@@scx],0       ; do scx 0
                jmp     short @@8       ; wróć
        @@9:    popf                    ; czy został jakiś bajt na koniec ?
                jnc     @@10            ; nie - skocz dalej
                xor     al,al           ; jesteś już w tym niezły (ile można ?)
                rol     bl,1
                sbb     al,0
                and     ax,si
                stosb
; z kolei powyższe spawdzenia rejestrów DI i CX mają na celu zminimalizowanie
; liczby wołań funkcji setseg - to po pierwsze, po drugie umożliwia to przesyłanie
; słów a nie pojedyńczych bajtów co wydatnie skraca czas wypełniania - tak
; około dwóch razy; ten trick jest też w funkcjach savebitmap i restorebitmap
        @@10:   mov     di,[@@sdi]      ; do DI to co zapamiętałeś na początku
                add     di,[pix_per_line]       ; tu przechodzisz do następnej linii
                adc     [@@sdl],0       ; tu -> nr segmentu
                inc     [@@Y1]          ; uaktualnij Y
                mov     bx,[@@Y1]       ; prześlij do BX (będzie tu potrzebny u góry)
                cmp     bx,[@@Y2]       ; koniec ?
                jbe     @@3             ; nie -> skocz z powrotem
                jmp     @@21            ; tak -> kończymy
        @@11:   xor     ax,ax           ; a tutaj jest wypełnianie SOLID
                cmp     [fill_no],0     ; lub BACKGROUND, prawie tak samo
                je      @@12            ; jak wyżej, tylko prościej, więc
                mov     al,[fill_color] ; znowu musisz liczyć na własne siły
                mov     ah,al
        @@12:   mov     si,ax
        @@13:   mov     [@@sdi],di
                and     bx,7
                mov     bl,[fill_style+bx]
                mov     cl,[byte ptr @@X1]
                and     cl,7
                rol     bl,cl
                mov     cx,[@@deltaX]
                mov     al,[@@sdl]
                cmp     [current_map],al
                je      @@14
                mov     [current_map],al
                call    setseg
        @@14:   test    di,1
                jz      @@15
                dec     cx
                mov     ax,si
                stosb
                or      di,di
                jnz     @@15
                mov     al,[current_map]
                inc     al
                mov     [current_map],al
                call    setseg
        @@15:   shr     cx,1
                pushf
                jcxz    @@19
                shl     cx,1
                mov     [@@scx],cx
                neg     cx
                cmp     di,cx
                ja      @@17
                neg     cx
                shr     cx,1
                mov     [@@scx],0
                jmp     @@18
        @@17:   mov     cx,di
                neg     cx
                sub     [@@scx],cx
                shr     cx,1
        @@18:   mov     ax,si
                rep     stosw
                or      di,di
                jnz     @@19
                mov     al,[current_map]
                inc     al
                mov     [current_map],al
                call    setseg
                cmp     [@@scx],0
                je      @@19
                mov     cx,[@@scx]
                shr     cx,1
                mov     [@@scx],0
                jmp     short @@18
        @@19:   popf
                jnc     @@20
                mov     ax,si
                stosb
        @@20:   mov     di,[@@sdi]
                add     di,[pix_per_line]
                adc     [@@sdl],0
                inc     [@@Y1]
                mov     bx,[@@Y1]
                cmp     bx,[@@Y2]
                jbe     @@13
        @@21:   ret
ENDP            patbar

; PALETTE
; Ładuje wejście w palecie
;    wejście :  AX - numer indeksu i kod funkcji
;               BX - wartość koloru do załadowania w palecie
;    wyjście :  brak
; Dwa najstarsze bity w AX determinują akcję do podjęcia wg schematu:
;     00 : BX zawiera kolor, AX - indeks
;     01 : nie używane
;     10 : BX - czerwień, CX - zieleń, DX - niebieski, AX - indeks
;     11 : BX - kolor tła

PROC            palette         NEAR
                test    ah,80h          ; ustaw wejście w palecie ?
                jnz     @@2             ; nie -> skocz
        @@1:    mov     bh,bl           ; tak -> do BH nr koloru
                mov     bl,al           ; do BL nr rejestru
                mov     ax,1000h        ; funkcja 10h podfunkcja 0
                int     10h             ; przerwania 10h
                ret
        @@2:    test    ah,40           ; ustaw kolor tła ?
                jz      @@3             ; nie -> skocz
                xor     al,al           ; tak -> w AL nr rejestru koloru tła
                jmp     short @@1       ; skocz powyżej
        @@3:    mov     dh,bl           ; do DH składowa czerwieni
                mov     ch,cl           ; do CH składowa zieleni
                mov     cl,dl           ; do DL składowa niebieskiego
                xor     bh,bh           ; do BX nr rejestru
                mov     bl,al
                mov     ax,1010h        ; funkcja 10h podfunkcja 10h
                int     10h             ; przerwania 10h
                ret
ENDP            palette

; ALLPALETTE
; Ładuje pełną paletę
;    wejście :  ES : BX - tablica wejść do palety
;    wyjście :  brak

PROC            allpalette      NEAR
                mov     ax,1002h        ; funkcja 10h podfunkcja 2h
                mov     dx,bx           ; do DX offset tablicy z wartościami kolorów
                int     10h             ; przerwanie 10h
                ret
ENDP            allpalette

; COLOR
; Ładuje kolor wykreślania
;    wejście :  AL - kolor wykreślania
;               AH - kolor wypełniania
;    wyjście :  brak

PROC            color           NEAR
                mov     [word draw_color],ax    ; zapamiętaj kolor
                ret                     ; wykreślania i wypełniania
ENDP            color

; FILLSTYLE
; Ustawia styl wypełniania
;    wejście :  AL - numer standardowego wzorca wypełniania
;               ES : BX - wskaźnik do tablicy z wzorcem wypełniania definiowanym
;                         przez użytkownika jeśli AL = 0FFh
;    wyjście :  brak

PROC            fillstyle       NEAR
                mov     [fill_no],al    ; zapamiętaj nr wypełniacza
                cmp     al,1            ; wypełnianie SOLID lub BACKGROUND ?
                ja      @@1             ; nie -> skocz
                neg     al
                mov     ah,ah           ; AL do AH
                mov     cx,4            ; liczba przesłań = 4
                mov     es,[DGROUP@]    ; do ES adres segmentowy
                mov     di,offset fill_style    ; do DI offset
                rep     stosw           ; prześlij wzorzec
                ret
        @@1:    cmp     al,0FFh         ; wzór użytkownika ?
                je      @@2             ; tak -> skocz
                xor     ah,ah           ; zeruj AH
                sub     al,2            ; odejmij od AL 2
                shl     al,1            ; mnóż AL przez 8
                shl     al,1
                shl     al,1
                mov     si,offset fill_styles   ; do SI adres tablicy z wzorami
                add     si,ax           ; tu w SI adres potrzebnego wzoru
                mov     es,[DGROUP@]    ; do ES zaś segment
                jmp     short @@3       ; skocz dalej
        @@2:    mov     [fill_no],0Ch   ; zapamiętaj nr wzoru użytkownika
                mov     ax,es           ; załaduj DS segmentem źródła
                mov     es,[DGROUP@]    ; do ES zaś segment
                mov     ds,ax
                mov     si,bx           ; a SI offsetem
        @@3:    mov     di,offset fill_style    ; do DI offset przeznaczenia
                mov     cx,0004h        ; liczba słów do przesłania
                rep     movsw           ; prześlij
                ret
ENDP            fillstyle

; LINESTYLE
; Ustawia styl wykreślania linii
;    wejście :  AL - numer predefiniowanego wzorca
;               BX - wzorzec użytkownika gdy AL = 4
;               CX - grubość linii
;    wyjście :  brak

PROC            linestyle       NEAR
                mov     [line_width],cl ; zapamiętaj nr wzoru
                cmp     al,4            ; wzór użytkownika ?
                jne     @@1             ; nie -> skocz
                mov     [line_style],bx ; zapamiętaj wzór użytkownika
                ret
        @@1:    xor     ah,ah           ; zeruj AH
                shl     ax,1            ; mnóż AX przez 2
                add     ax,offset line_styles   ; dodaj offset tablicy wzorów
                mov     si,ax           ; do SI adres wzorca
                lodsw                   ; wzorzec do AX
                mov     [line_style],ax ; i do swojej zmiennej
                ret
ENDP            linestyle

; TEXTSTYLE
; Ustawia parametry fontu sprzętowego
;    wejście :  AL - numer fontu
;               AH - orientacja fontu
;                    0 - normalna
;                    1 - 90 stopni
;                    2 - w dół
;               BX - żądany rozmiar poziomy
;               CX - żądany rozmiar pionowy
;    wyjście :  BX - najbliższy rozmiar poziomy
;               CX - najbliższy rozmiar pionowy

PROC            textstyle       NEAR
                mov     [word ptr font_number],ax       ; zapamiętaj nr i orientację fontu
                and     bx,0F8h         ; tu w BX najliższy dostępny rozmiar X
                and     cx,0F8h         ; a w CX rozmiar Y
                mov     [fontXsize],bx  ; zapamiętaj X
                mov     [fontYsize],cx  ; i Y
                mov     dx,bx           ; wyznacz mnożnik X
                shr     dl,1
                shr     dl,1
                shr     dl,1
                mov     [fontXmult],dl
                or      dl,dl
                jnz     @@1
                inc     dl
        @@1:    shl     dl,1            ; i margines X
                shl     dl,1
                shl     dl,1
                dec     dx
                mov     [fontXmarg],dx
                mov     dx,cx           ; oraz mnożnik Y
                shr     dl,1
                shr     dl,1
                shr     dl,1
                mov     [fontYmult],dl
                or      dl,dl
                jnz     @@2
                inc     dl
        @@2:    shl     dl,1            ; i margines Y
                shl     dl,1
                shl     dl,1
                dec     dx
                mov     [fontYmarg],dx
                ret
ENDP            textstyle

; TEXT
; Wyprowadzenie tekstu od CP
;    wejście :  ES : BX - wskaźnik do tekstu ASCII
;               CX - długość tekstu (w znakach)
;    wyjście :  brak

PROC            text            NEAR
                cld
                cmp     [font_orient],0
                je      @@1
                cmp     [font_orient],3
                je      @@1
                add     bx,cx
                dec     bx
                std
        @@1:    mov     si,bx
                cmp     [font_orient],0
                je      @@2
                cmp     [font_orient],2
                je      @@2
                mov     bx,offset current_y
                mov     ax,[fontYsize]
                jmp     @@3
        @@2:    mov     bx,offset current_x
                mov     ax,[fontXsize]
        @@3:    push    es              ; zachowaj te rejestry na później
                push    ax
                push    bx
                push    cx
                lods    [byte es:si]
                push    si
                pushf
                mov     bx,[current_x]  ; do BX współrzędna X
                mov     cx,[current_y]  ; a do CX - Y
                call    draw_letter     ; wykreśl literę
                popf
                pop     si
                pop     cx              ; odtwórz rejestry
                pop     bx
                pop     ax
                pop     es
                add     [bx],ax
                loop    @@3             ; sprawdź czy koniec, nie -> skocz
                ret
ENDP            text

; DRAW_LETTER
; Funkcja wykreśla jedną literę
;    wejście :  AL - kod ASCII znaku do wykreślenia
;               BX - współrzędna X
;               CX - współrzędna Y
;    wyjście :  brak

PROC            draw_letter     NEAR
                LOCAL   @@X : WORD, @@Y : WORD, @@Xr : WORD
                cmp     bx,[left_x]
                jl      @@7
                mov     dx,[right_x]
                sub     dx,[fontXmarg]
                cmp     bx,dx
                ja      @@7
                cmp     cx,[top_y]
                jl      @@7
                mov     dx,[bottom_y]
                sub     dx,[fontYmarg]
                cmp     cx,dx
                ja      @@7
                mov     [@@X],bx
                mov     [@@Y],cx
                call    prepare_table
                mov     cx,8
                mov     bl,[draw_color]
        @@1:    mov     bh,[es:di]
                inc     di
                push    es
                mov     es,[video_adr]
                push    cx
                xor     ch,ch
                mov     cl,[fontYmult]
        @@2:    push    cx
                mov     ax,[@@X]
                mov     [@@Xr],ax
                mov     cx,8
        @@3:    push    cx
                xor     ch,ch
                mov     cl,[fontXmult]
                rol     bh,1
                jnc     @@6
                mov     si,[@@Xr]
                mov     ax,[@@Y]
                mul     [pix_per_line]
                add     si,ax
                adc     dx,0
        @@4:    cmp     dl,[current_map]
                je      @@5
                mov     al,dl
                mov     [current_map],dl
                call    setseg
        @@5:    mov     [es:si],bl
                mov     dl,[current_map]
                add     si,1
                adc     dl,0
                loop    @@4
        @@6:    xor     ah,ah
                mov     al,[fontXmult]
                add     [@@Xr],ax
                pop     cx
                loop    @@3
                pop     cx
                inc     [@@Y]
                loop    @@2
                pop     cx
                pop     es
                loop    @@1
        @@7:    ret
ENDP            draw_letter

; PREPARE_TABLE
; Zwraca wskaźnik do ośmiobajtowej tablicy ze wzorcem znaku do wykreślenia
;    wejście :  AL - kod znaku do wykreślenia
;    wyjście :  ES : DI - wskaźnik do tablicy

PROC            prepare_table
                cld
                or      al,al
                jns     @@1
                sub     al,80h
                les     di,[font8x8hi]
                jmp     @@2
        @@1:    les     di,[font8x8lo]
        @@2:    xor     ah,ah
                shl     ax,1
                shl     ax,1
                shl     ax,1
                add     di,ax
                cmp     [font_orient],0
                je      @@13
                push    bp
                mov     bp,8
                mov     ax,[es:di]
                mov     bx,[es:di+2]
                mov     cx,[es:di+4]
                mov     dx,[es:di+6]
                mov     es,[DGROUP@]
                mov     di,offset font_buffer
                cmp     [font_orient],1
                jne     @@5
        @@4:    shr     al,1
                rcl     si,1
                shr     ah,1
                rcl     si,1
                shr     bl,1
                rcl     si,1
                shr     bh,1
                rcl     si,1
                shr     cl,1
                rcl     si,1
                shr     ch,1
                rcl     si,1
                shr     dl,1
                rcl     si,1
                shr     dh,1
                rcl     si,1
                xchg    ax,si
                stosb
                xchg    ax,si
                dec     bp
                jnz     @@4
                jmp     @@12
        @@5:    cmp     [font_orient],2
                jne     @@11
        @@6:    mov     bp,cx
                mov     cx,16
        @@7:    shr     dx,1
                rcl     si,1
                loop    @@7
                xchg    ax,si
                stosw
                mov     ax,si
                mov     dx,bp
                mov     cx,16
        @@8:    shr     dx,1
                rcl     si,1
                loop    @@8
                xchg    ax,si
                stosw
                mov     ax,si
                mov     cx,16
        @@9:    shr     bx,1
                rcl     si,1
                loop    @@9
                xchg    ax,si
                stosw
                mov     ax,si
                mov     cx,16
        @@10:   shr     ax,1
                rcl     si,1
                loop    @@10
                mov     ax,si
                stosw
                jmp     @@12
        @@11:   shl     dh,1
                rcl     si,1
                shl     dl,1
                rcl     si,1
                shl     ch,1
                rcl     si,1
                shl     cl,1
                rcl     si,1
                shl     bh,1
                rcl     si,1
                shl     bl,1
                rcl     si,1
                shl     ah,1
                rcl     si,1
                shl     al,1
                rcl     si,1
                xchg    ax,si
                stosb
                xchg    ax,si
                dec     bp
                jnz     @@11
        @@12:   pop     bp
                mov     di,offset font_buffer
        @@13:   ret
ENDP            prepare_table

; TEXTSIZ
; Zwraca szerokość i wysokość tekstu
;    wejście :  ES : BX - wskaźnik do tekstu ASCII
;               CX - długość tekstu (w znakach)
;    wyjście :  BX - szerokość w pikselach
;               CX - wysokość w pikselach

PROC            textsiz         NEAR
                mov     ax,cx
                mul     [fontXsize]
                mov     bx,ax
                mov     cx,[fontYsize]
                ret
ENDP            textsiz

; GETPIXEL
; Odczytuje kolor piksela
;    wejście :  AX - współrzędna X
;               BX - współrzędna Y
;    wyjście :  DL - kolor piksela

PROC            getpix          NEAR
                mov     es,[video_adr]  ; segment video do ES
                xchg    ax,bx
                mul     [pix_per_line]  ; liczba pikseli na linię
                add     bx,ax           ; dodaj AX do DI (X1)
                adc     dl,0            ; w DL nr segmentu na karcie
                cmp     dl,[current_map]
                je      @@1
                mov     al,dl
                mov     [current_map],al
                call    setseg
        @@1:    mov     dl,[es:bx]      ; w DL kolor piksela
                ret
ENDP            getpix

; PUTPIXEL
; Zapisuje piksel
;    wejście :  AX - współrzędna X
;               BX - współrzędna Y
;               DL - kolor piksela
;    wyjście :  brak

PROC            putpix          NEAR
                mov     es,[video_adr]
                mov     ch,dl
                xchg    ax,bx
                mul     [pix_per_line]
                add     bx,ax
                adc     dl,0
                cmp     dl,[current_map]
                je      @@1
                mov     al,dl
                mov     [current_map],al
                call    setseg
        @@1:    mov     [es:bx],ch
                ret
ENDP            putpix

; BITMAPUTIL
; Pytanie o tablicę funkcji dodatkowych
;    wejście :  brak
;    wyjście :  ES : BX - wskaźnik do tablicy funkcji dodatkowych

PROC            bitmaputil      NEAR
                mov     es,[DGROUP@]
                mov     bx,offset BITMAPUTILVEC
                ret
ENDP            bitmaputil

; SAVEBITMAP
; Zapis fragmentu obrazu w pamięci systemowej
;    wejście :  CX - współrzędna X lewego górnego rogu obrazu
;               DX - współrzędna Y lewego górnego rogu obrazu
;               ES : BX - wskaźnik do bufora
;               [ES : BX] - szerokość prostokąta minus 1
;               [ES : BX+2] - wysokość prostokąta minus 1
;    wyjście :  brak

PROC            savebitmap      NEAR
                USES    bp
                mov     di,[es:bx+2]    ; deltaY do DI
                mov     si,[es:bx]      ; deltaX do SI
                inc     si              ; w SI licznik
                xchg    si,cx           ; licznik do CX, X1 do SI
                mov     ax,[pix_per_line]       ; do AX szerokość linii
                mov     bp,ax           ; do BP szerokość linii
                sub     bp,cx           ; pomniejsz BP o licznik
                mul     dx              ; mnóż AX przez DX (Y1)
                add     si,ax           ; dodaj AX do SI (X1)
                adc     dl,0            ; w DL nr segemntu na karcie
                mov     al,dl           ; DL do AL
                add     bx,4            ; BX wskazuje na pierwszy wolny bajt bufora
        @@1:    push    cx              ; zachowaj CX
                cmp     al,[current_map]; czy przeprogramować kartę ?
                je      @@2
                mov     [current_map],al
                call    setseg
                mov     al,[current_map]
        @@2:    mov     ds,[video_adr]
                ASSUME  ds : NOTHING
        @@3:    mov     ah,[si]         ; pobierz piksel
                mov     [es:bx],ah      ; i zapamiętaj go
                inc     si              ; zwiększ SI
                jnz     @@4             ; jeśli SI == 0 to przeprogramuj kartę
                inc     al
                push    ds
                mov     ds,[DGROUP@]
                ASSUME  ds : @data
                mov     [current_map],al
                call    setseg
                mov     al,[current_map]
                pop     ds
                ASSUME  ds : NOTHING
        @@4:    inc     bx              ; zwiększ BX
                jnz     @@5             ; jeśli BX == 0 to uaktualnij ES
                push    ds
                mov     ds,[DGROUP@]
                ASSUME  ds : @data
                mov     dx,es           ; ES do DX
                add     dx,[sel_inc]    ; DX <- DX + 1000h
                mov     es,dx           ; DX do ES
                pop     ds
                ASSUME  ds : NOTHING
        @@5:    loop    @@3             ; prześlij całą linię
                pop     cx              ; odtwórz licznik
                add     si,bp           ; przejdź do następnej linii
                adc     al,0            ; uaktualnij nr segmentu
                dec     di              ; zmniejsz liczbę linii do przesłania
                mov     ds,[DGROUP@]
                ASSUME  ds : @data
                jns     @@1             ; DI >= 0 to skocz
                ret                     ; nie -> to koniec
ENDP            savebitmap

; RESTOREBITMAP
; Odczyt fragmentu obrazu z pamięci systemowej
;    wejście :  AL - operacja logiczna do uźycia przy transferze:
;                    1 - zapis
;                    2 - XOR
;                    3 - OR
;                    4 - AND
;                    5 - zapis z negacją
;               CX - współrzędna X lewego górnego rogu obrazu
;               DX - współrzędna Y lewego górnego rogu obrazu
;               ES : BX - wskaźnik do bufora
;               [ES : BX] - szerokość prostokąta minus 1
;               [ES : BX+2] - wysokość prostokąta minus 1
;    wyjście :  brak

PROC            restorebitmap   NEAR
; działanie analogiczne do działania poprzedniej procedury, więc nie komentuję
; uwagi wstępne też są identyczne
                LOCAL   @@PutRoutine : WORD, @@add : WORD
                mov     di,[es:bx+2]
                mov     si,[es:bx]
                inc     si
                xchg    si,cx
                xor     ah,ah
                push    ax
                mov     ax,[pix_per_line]
                mov     [@@add],ax
                sub     [@@add],cx
                mul     dx
                add     si,ax
                adc     dl,0
                mov     al,dl
                add     bx,4
                pop     dx
                xchg    bx,dx
                shl     bx,1
                mov     bx,[bx+@@jumptable]
                mov     [@@PutRoutine],bx
                mov     bx,dx
        @@1:    push    cx
                cmp     al,[current_map]
                je      @@2
                mov     [current_map],al
                call    setseg
                mov     al,[current_map]
        @@2:    mov     ds,[video_adr]
                ASSUME  ds : NOTHING
        @@3:    mov     ah,[es:bx]
                call    [@@PutRoutine]
                inc     si
                jnz     @@4
                inc     al
                push    ds
                mov     ds,[DGROUP@]
                ASSUME  ds : @data
                mov     [current_map],al
                call    setseg
                mov     al,[current_map]
                pop     ds
                ASSUME  ds : NOTHING
        @@4:    inc     bx
                jnz     @@5
                push    ds
                mov     ds,[DGROUP@]
                ASSUME  ds : @data
                mov     dx,es
                add     dx,[sel_inc]
                mov     es,dx
                pop     ds
                ASSUME  ds : NOTHING
        @@5:    loop    @@3
                pop     cx
                add     si,[@@add]
                adc     al,0
                mov     ds,[DGROUP@]
                ASSUME  ds : @data
                dec     di
                jns     @@1
                ret
@@NotPut:       not     ah
@@CopyPut:      mov     [si],ah
                retn
@@XorPut:       xor     [si],ah
                retn
@@OrPut:        or      [si],ah
                retn
@@AndPut:       and     [si],ah
                retn
@@jumptable     dw      @@CopyPut
                dw      @@XorPut
                dw      @@OrPut
                dw      @@AndPut
                dw      @@NotPut
ENDP            restorebitmap

                ASSUME ds : @data

; SETCLIP
; Definiuje okienko obcinające
;    wejście :  AX = X1
;               BX = Y1
;               CX = X2
;               DX = Y2
;    wyjście :  brak

PROC            setclip         NEAR
                mov     [left_x],ax
                mov     [top_y],bx
                mov     [right_x],cx
                mov     [bottom_y],dx
                ret
ENDP            setclip

; COLOR_QUERY
; 1. Pytanie o rozmiar tablicy kolorów
;    wejście :  AL = 0
;    wyjście :  BX - rozmiar tablicy koloru
;               CX - maksymalna liczba kolorów
; 2. Pytanie o domyślną tablicę kolorów
;    wejście :  AL = 1
;    wyjście :  ES : BX - wskaźnik do domyślnej tablicy kolorów

PROC            color_query     NEAR
                cmp     al,0
                jne     @@1
                mov     cx,255
                mov     bx,16
                ret
          @@1:  mov     es,[DGROUP@]
                mov     bx,offset default_palette
                ret
ENDP            color_query

; GOTOGRAPHIC
; Wprowadzenie trybu pikselowego
;    wejście :  brak
;    wyjście :  brak

PROC            gotographic     FAR
                ret
ENDP            gotographic

; EXITGRAPHIC
; Opuszczenie trybu pikselowego
;    wejście :  brak
;    wyjście :  brak

PROC            exitgraphic     FAR
                ret
ENDP            exitgraphic

                ASSUME  ds : NOTHING

; PUTPIXEL
; Zapisuje piksel
;    wejście :  AX - współrzędna X
;               BX - współrzędna Y
;               DL - kolor piksela
;    wyjście :  brak
PROC            putpixel        FAR
                USES    ds
                mov     ds,[DGROUP@]
                call    putpix
                ret
ENDP            putpixel

; GETPIXEL
; Odczytuje kolor piksela
;    wejście :  AX - współrzędna X
;               BX - współrzędna Y
;    wyjście :  DL - kolor piksela
PROC            getpixel        FAR
                USES    ds
                mov     ds,[DGROUP@]
                call    getpix
                ret
ENDP            getpixel

; BITS_PIX
; Zwraca liczbę bitów na piksel
;    wejście :  brak
;    wyjście :  AX - liczba bitów na piksel

PROC            bits_pix        FAR
                mov     ax,8
                ret
ENDP            bits_pix

; SETDRAWPAGE
; Ustawia stronę aktywną
;    wejście :  AL - numer strony aktywnej
;    wyjście :  brak
;
; SETVISUALPAGE
; Ustawia stronę wyświetlaną
;    wejście :  AL - numer strony wyświetlanej
;    wyjście :  brak
;
; Obie funkcje identyczne - nie powielamy kodu

PROC            setpage FAR
                USES    ds
                mov     ds,[DGROUP@]
                ASSUME  ds : @data
                cmp     al,00h
                je      @@1
                mov     bx,[current_status]
                mov     [($status ptr bx).$stat],grError
        @@1:    ret
ENDP            setpage

                ASSUME  ds : NOTHING

; SETWRITEMODE
; Ustawia tryb wykreślania
;    wejście :  AX - sposób wykreślania
;                    0 - zapis
;                    1 - XOR
;    wyjście :  brak

PROC            setwritemode    FAR
                USES    ds
                mov     ds,[DGROUP@]
                ASSUME  ds : @data
                mov     [write_mode],COPY_PUT
                or      ax,ax
                jz      @@1
                mov     [write_mode],XOR_PUT
        @@1:    ret
ENDP            setwritemode

PROC            ScanDownForBorder
                ARG     @@X : WORD, @@Y : WORD
                mov     ax,[@@X]
                jmp     @@2
        @@1:    push    ax
                mov     bx,[@@Y]
                call    getpix
                pop     ax
                cmp     dl,[BorderColor]
                je      @@3
                dec     ax
        @@2:    cmp     ax,[left_x]
                jge     @@1
        @@3:    inc     ax
                ret
ENDP

PROC            ScanUpForBorder
                ARG     @@X : WORD, @@Y : WORD
                mov     ax,[@@X]
                jmp     @@2
        @@1:    push    ax
                mov     bx,[@@Y]
                call    getpix
                pop     ax
                cmp     dl,[BorderColor]
                je      @@3
                inc     ax
        @@2:    cmp     ax,[right_x]
                jle     @@1
        @@3:    dec     ax
                ret
ENDP

PROC            ScanUpForNotBorder
                ARG     @@X : WORD, @@XMAX : WORD, @@Y : WORD
                mov     ax,[@@X]
                jmp     @@2
        @@1:    push    ax
                mov     bx,[@@Y]
                call    getpix
                pop     ax
                cmp     dl,[BorderColor]
                jne     @@3
                inc     ax
        @@2:    cmp     ax,[@@XMAX]
                jle     @@1
                mov     ax,-1
        @@3:    ret
ENDP

PROC            PopPoint
                ARG     @@X : WORD, @@Y : WORD, @@DeltaY : WORD
                mov     si,[@@X]
                mov     di,[@@Y]
                cmp     [@@DeltaY],0
                jge     @@1
                not     si
        @@1:    mov     bx,[StackStart]
        @@2:    cmp     si,[ss:bx]
                jne     @@3
                cmp     di,[ss:bx+2]
                je      @@4
        @@3:    add     bx,4
                cmp     bx,[StackCurr]
                jb      @@2
                xor     ax,ax
                jmp     @@5
        @@4:    mov     di,bx
                lea     si,[bx+4]
                sub     [StackCurr],4
                sub     bx,[StackCurr]
                neg     bx
                shr     bx,1
                mov     cx,bx
                mov     dx,ds
                mov     bx,ss
                mov     ds,bx
                mov     es,bx
                cld
                rep     movsw
                mov     ds,dx
                mov     ax,1
        @@5:    ret
ENDP

PROC            PushPoint
                ARG     @@X : WORD, @@MAXX : WORD, @@Y : WORD, @@DeltaY : WORD
        @@1:    call    ScanUpForNotBorder, [@@X], [@@MAXX], [@@Y]
                or      ax,ax
                jl      @@3
                mov     bx,[StackCurr]
                add     [StackCurr],4
                mov     [ss:bx],ax
                mov     dx,[@@Y]
                mov     [ss:bx+2],dx
                cmp     [@@DeltaY],0
                jge     @@2
                not     [word ss:bx]
        @@2:    call    ScanUpForBorder, ax, dx
                inc     ax
                mov     [@@X],ax
                jmp     @@1
        @@3:    ret
ENDP

PROC            Scanner
                ARG     @@X : WORD, @@Y : WORD, @@DeltaY : WORD
                LOCAL   @@ny : WORD, @@lx : WORD, @@i : WORD, @@y1 : WORD, \
                        @@x1 : WORD, @@x2 : WORD, @@dy : WORD
        @@1:    mov     bx,[@@Y]
                add     bx,[@@DeltaY]
                cmp     bx,[top_y]
                jl      @@10
                cmp     bx,[bottom_y]
                jg      @@10
                mov     [@@ny],bx
                mov     ax,[@@X]
                call    getpix
                cmp     dl,[BorderColor]
                je      @@2
                call    ScanDownForBorder, [@@X], [@@ny]
                jmp     @@3
        @@2:    call    ScanUpForNotBorder, [@@X], [UpXLimit], [@@ny]
                or      ax,ax
                jl      @@10
        @@3:    mov     [@@lx],ax
                call    ScanUpForBorder, ax, [@@ny]
                mov     cx,ax
                xchg    ax,[UpXLimit]
                mov     [UpXLimit1],ax
                mov     ax,[@@lx]
                mov     bx,[@@ny]
                mov     dx,bx
                call    patbar
                mov     ax,[@@X]
                dec     ax
                mov     bx,[@@DeltaY]
                neg     bx
                call    PushPoint, [@@lx], ax, [@@Y], bx
                mov     ax,[UpXLimit]
                mov     bx,[UpXLimit1]
                cmp     ax,bx
                je      @@9
                mov     cx,[@@DeltaY]
                jb      @@4
                mov     [@@x1],ax
                mov     [@@i],ax
                mov     [@@x2],bx
                jmp     @@5
        @@4:    mov     [@@x1],bx
                mov     [@@i],bx
                mov     [@@x2],ax
                neg     cx
                mov     dx,[@@ny]
                mov     [@@Y],dx
        @@5:    mov     [@@dy],cx
                inc     [@@x2]
                call    ScanUpForBorder, [@@x1], [@@Y]
                cmp     ax,[@@x1]
                jle     @@8
                mov     bx,[@@Y]
                add     bx,[@@dy]
                mov     [@@y1],bx
        @@6:    mov     [@@i],ax
                call    ScanUpForBorder, ax, [@@y1]
                cmp     ax,[@@i]
                jle     @@7
                mov     [@@i],ax
                call    ScanUpForBorder, ax, [@@Y]
                cmp     ax,[@@i]
                jg      @@6
        @@7:    mov     bx,[@@x1]
                inc     bx
                call    PushPoint, bx, [@@i], [@@y1], [@@dy]
        @@8:    neg     [@@dy]
                call    PushPoint, [@@x2], [@@i], [@@Y], [@@dy]
        @@9:    mov     ax,[@@lx]
                mov     bx,[@@ny]
                mov     cx,[@@DeltaY]
                mov     [@@X],ax
                mov     [@@Y],bx
                neg     cx
                call    PopPoint, ax, bx, cx
                or      ax,ax
                je      @@1
        @@10:   ret
ENDP

PROC            floodfill
                LOCAL   @@X : WORD, @@Y : WORD, @@DeltaY : WORD, \
                        @@Stack[256] : DWORD
                mov     [@@DeltaY],-1
                mov     [BorderColor],cl
                mov     [@@X],ax
                mov     [@@Y],bx
                call    getpix
                cmp     dl,[BorderColor]
                je      @@5
                call    ScanDownForBorder, [@@X], [@@Y]
                mov     [@@X],ax
                mov     [word @@Stack],ax
                mov     ax,[@@Y]
                mov     [word @@Stack+2],ax
                lea     ax,[@@Stack]
                mov     [StackStart],ax
                add     ax,4
                mov     [StackCurr],ax
                call    ScanUpForBorder, [@@X], [@@Y]
                mov     [UpXLimit],ax
        @@1:    call    Scanner, [@@X], [@@Y], [@@DeltaY]
        @@2:    mov     bx,[StackCurr]
                cmp     bx,[StackStart]
                je      @@5
                sub     [StackCurr],4
                mov     ax,[ss:bx-4]
                mov     dx,[ss:bx-2]
                or      ax,ax
                jl      @@3
                mov     [@@DeltaY],1
                jmp     @@4
        @@3:    not     ax
                mov     [@@DeltaY],-1
        @@4:    mov     [@@X],ax
                mov     [@@Y],dx
                call    ScanUpForBorder, ax, dx
                mov     cx,ax
                xchg    ax,[UpXLimit]
                mov     [UpXLimit1],ax
                mov     ax,[@@X]
                mov     bx,[@@Y]
                mov     dx,bx
                call    patbar
                mov     ax,[@@DeltaY]
                neg     ax
                call    PopPoint, [@@X], [@@Y], ax
                or      ax,ax
                jne     @@2
                jmp     @@1
        @@5:    ret
ENDP

PROC            DrawCursor      NEAR
                ARG     @@X : WORD, @@Y : WORD
                LOCAL   @@l : WORD, @@add : WORD, @@dy : WORD
                USES    ds
                mov     bx,[current_status]
                mov     [@@l],8000h
                mov     ax,[MHotSpotX]
                sub     [@@X],ax
                jge     @@1
                mov     cx,[@@X]
                mov     ax,cx
                add     ax,15
                neg     cl
                shr     [@@l],cl
                mov     [@@X],0
                jmp     @@2
        @@1:    mov     ax,[($status ptr bx).$xres]
                sub     ax,[@@X]
                cmp     ax,15
                jl      @@2
                mov     ax,15
                jmp     @@3
        @@2:    or      ax,ax
                jge     @@3
                mov     [MBufferEmpty],1
                jmp     @@14
        @@3:    mov     [MOlddx],ax
                mov     dx,[pix_per_line]
                sub     dx,ax
                dec     dx
                mov     [@@add],dx
                mov     ax,[MHotSpotY]
                sub     [@@Y],ax
                jge     @@4
                mov     cx,[@@Y]
                mov     ax,cx
                add     ax,15
                neg     cx
                shl     cx,1
                mov     [@@Y],0
                jmp     @@5
        @@4:    xor     cx,cx
                mov     ax,[($status ptr bx).$yres]
                sub     ax,[@@Y]
                cmp     ax,15
                jl      @@5
                mov     ax,15
                jmp     @@6
        @@5:    or      ax,ax
                jge     @@6
                mov     [MBufferEmpty],1
                jmp     @@14
        @@6:    mov     [MBufferEmpty],0
                mov     [MOlddy],ax
                mov     [@@dy],ax
                mov     ax,[@@X]
                mov     [MOldX],ax
                mov     ax,[@@Y]
                mov     [MOldY],ax
                mov     ax,ds
                mov     es,ax
                ASSUME  es : @data
                mov     ds,[video_adr]
                ASSUME  ds : NOTHING
                mov     si,[@@X]
                mov     ax,[@@Y]
                mul     [pix_per_line]
                add     si,ax
                adc     dl,0
                cmp     dl,[current_map]
                je      @@7
                mov     al,dl
                mov     [current_map],al
                call    setseg
        @@7:    mov     di,offset MBuffer
                mov     bx,cx
        @@8:    mov     dx,[@@l]
                mov     cx,[MOlddx]
                inc     cx
        @@9:    mov     al,[si]
                stosb
                test    dx,[MCursorTbl+bx]
                jnz     @@10
                xor     al,al
                test    dx,[MCursorTbl+bx+32]
                jz      @@11
                xor     al,15
                jmp     @@11
        @@10:   test    dx,[MCursorTbl+bx+32]
                jz      @@11
                xor     al,15
        @@11:   mov     [si],al
                inc     si
                jnz     @@12
                push    dx
                inc     [current_map]
                mov     al,[current_map]
                call    setseg
                pop     dx
        @@12:   shr     dx,1
                loop    @@9
                add     bx,2
                add     si,[@@add]
                jnc     @@13
                inc     [current_map]
                mov     al,[current_map]
                call    setseg
        @@13:   dec     [@@dy]
                jns     @@8
        @@14:   ret
ENDP

                ASSUME  ds : @data, es : NOTHING

PROC            RestoreBackground       NEAR
                LOCAL   @@dy : WORD
                cmp     [MBufferEmpty],0
                jne     @@6
                mov     ax,[MOlddy]
                mov     [@@dy],ax
                mov     es,[video_adr]
                mov     di,[MOldX]
                mov     ax,[pix_per_line]
                mov     bx,ax
                sub     bx,[MOlddx]
                dec     bx
                mul     [MOldY]
                add     di,ax
                adc     dl,0
                cmp     dl,[current_map]
                je      @@1
                mov     al,dl
                mov     [current_map],al
                call    setseg
        @@1:    mov     si,offset MBuffer
        @@2:    mov     cx,[MOlddx]
                inc     cx
        @@3:    lodsb
                mov     [es:di],al
                inc     di
                jnz     @@4
                inc     [current_map]
                mov     al,[current_map]
                call    setseg
        @@4:    loop    @@3
                add     di,bx
                jnc     @@5
                inc     [current_map]
                mov     al,[current_map]
                call    setseg
        @@5:    dec     [@@dy]
                jns     @@2
        @@6:    ret
ENDP

                ASSUME  ds : NOTHING

PROC            IntRoutine      FAR
                LOCAL   @@X : WORD, @@Y : WORD, @@OldMap : BYTE
                mov     ds,[DGROUP@]
                ASSUME  ds : @data
                mov     [@@X],cx
                mov     [@@Y],dx
                test    ax,[MUserMask]
                jz      @@1
                push    ax
                mov     ax,[word MUserRoutine]
                or      ax,[word MUserRoutine+2]
                pop     ax
                jz      @@1
                call    [MUserRoutine]
        @@1:    cmp     [MfDraw],0
                jl      @@6
                cli
                mov     al,[current_map]
                mov     [@@OldMap],al
                mov     ax,[@@X]
                cmp     ax,[MTrapX1]
                jl      @@2
                cmp     ax,[MTrapX2]
                jg      @@2
                mov     ax,[@@Y]
                cmp     ax,[MTrapY1]
                jl      @@2
                cmp     ax,[MTrapY2]
                jle     @@3
        @@2:    call    RestoreBackground
                call    DrawCursor, [@@X], [@@Y]
                jmp     @@4
        @@3:    mov     [MfDraw],-1
                call    RestoreBackground
        @@4:    mov     al,[@@OldMap]
                cmp     al,[current_map]
                je      @@5
                mov     [current_map],al
                call    setseg
        @@5:    sti
        @@6:    ret
ENDP

                ASSUME  ds : NOTHING

PROC            Int33h  FAR
                push    ax
                push    bx
                push    cx
                push    dx
                push    si
                push    di
                push    es
                push    ds
                push    bp
                mov     ds,[DGROUP@]
                ASSUME  ds : @data
                mov     bp,sp
                cmp     ax,0
                jne     @@1
                mov     [MUserMask],0
                mov     [MfDraw],-1
                mov     es,[DGROUP@]
                mov     si,offset MArrowCursor
                mov     di,offset MHotSpotX
                mov     cx,34
                rep     movsw
                mov     es,[Sel0040]
                mov     [byte es:49h],12h
                pushf
                call    [MOldInt33]
                mov     [bp+16],ax
                mov     [bp+14],bx
                mov     ax,2
                pushf
                call    [MOldInt33]
                xor     cx,cx
                mov     bx,[current_status]
                mov     dx,[($status ptr bx).$xres]
                mov     ax,7
                pushf
                call    [MOldInt33]
                xor     cx,cx
                mov     bx,[current_status]
                mov     dx,[($status ptr bx).$yres]
                mov     ax,8
                pushf
                call    [MOldInt33]
                mov     bx,[current_status]
                mov     cx,[($status ptr bx).$xres]
                shr     cx,1
                mov     dx,[($status ptr bx).$yres]
                shr     dx,1
                mov     ax,4
                pushf
                call    [MOldInt33]
                mov     cx,7Fh
                mov     dx,offset IntRoutine
                mov     ax,cs
                mov     es,ax
                mov     ax,12
                pushf
                call    [MOldInt33]
                jmp     @@9
        @@1:    cmp     ax,1
                jne     @@4
                cmp     [MfDraw],0
                je      @@3
                cmp     [MfDraw],-1
                jne     @@3
                mov     [MTrapX1],-1
                mov     [MTrapY1],-1
                mov     [MTrapX2],-1
                mov     [MTrapY2],-1
                mov     ax,3
                pushf
                call    [MOldInt33]
                call    DrawCursor, cx, dx
        @@2:    inc     [MfDraw]
        @@3:    jmp     @@9
        @@4:    cmp     ax,2
                jne     @@x2
                dec     [MfDraw]
                cmp     [MfDraw],-1
                jne     @@3
                call    RestoreBackground
                jmp     @@9
        @@x2:   cmp     ax,4
                jne     @@5
                cmp     [MfDraw],0
                jl      @@x3
                call    RestoreBackground
                call    DrawCursor, [word bp+12], [word bp+10]
        @@x3:   jmp     @@8
        @@5:    cmp     ax,9
                jne     @@6
                mov     [MHotSpotX],bx
                mov     [MHotSpotY],cx
                mov     si,dx
                mov     di,offset MCursorTbl
                mov     cx,32
                mov     bx,[DGROUP@]
                mov     ax,es
                mov     ds,ax
                mov     es,bx
                rep     movsw
                mov     ds,bx
                cmp     [MfDraw],0
                jl      @@3
                call    RestoreBackground
                mov     ax,3
                pushf
                call    [MOldInt33]
                call    DrawCursor, cx, dx
                jmp     @@9
        @@6:    cmp     ax,12
                jne     @@7
                mov     [MUserMask],cx
                mov     [word MUserRoutine],dx
                mov     [word MUserRoutine+2],es
                jmp     @@9
        @@7:    cmp     ax,16
                jne     @@x1
                mov     [MTrapX1],cx
                mov     [MTrapY1],dx
                mov     [MTrapX2],si
                mov     [MTrapY2],di
                jmp     @@9
        @@x1:   cmp     ax,20
                jne     @@8
                xchg    [MUserMask],cx
                xchg    [word MUserRoutine],dx
                mov     ax,es
                xchg    [word MUserRoutine+2],ax
                mov     [bp+12],cx
                mov     [bp+10],dx
                mov     [bp+4],ax
                jmp     @@9
        @@8:    mov     ax,[word MOldInt33+2]
                mov     bx,[word MOldInt33]
                xchg    ax,[bp+16]
                xchg    bx,[bp+14]
                pop     bp
                pop     ds
                ASSUME  ds : NOTHING
                pop     es
                pop     di
                pop     si
                pop     dx
                pop     cx
                retf
        @@9:    pop     bp
                pop     ds
                pop     es
                pop     di
                pop     si
                pop     dx
                pop     cx
                pop     bx
                pop     ax
                iret
ENDP

                ASSUME  ds : @data

PROC            InstallMouse    NEAR
                mov     ax,3533h
                int     21h
                mov     [word MOldInt33+2],es
                mov     [word MOldInt33],bx
                mov     ax,es
                or      ax,bx
                jz      @@1
                cmp     [byte es:bx],0CFh
                je      @@1
                xor     ax,ax
                int     33h
                cmp     ax,-1
                jne     @@1
                push    ds
                mov     ax,cs
                mov     ds,ax
                mov     dx,offset Int33h
                mov     ax,2533h
                int     21h
                pop     ds
        @@1:    ret
ENDP

PROC            UninstallMouse  NEAR
                push    ds
                lds     dx,[MOldInt33]
                mov     ax,2533h
                int     21h
                pop     ds
                mov     ax,[word MOldInt33]
                or      ax,[word MOldInt33+2]
                jz      @@1
                xor     cx,cx
                xor     dx,dx
                mov     es,dx
                mov     ax,12
                int     33h
        @@1:    ret
ENDP

END
